package com.cyk.like_test.api;

import com.baomidou.mybatisplus.extension.toolkit.Db;
import com.cyk.like_test.model.entity.AlbumLike;
import com.cyk.like_test.model.entity.AlbumStat;
import com.cyk.like_test.model.entity.AlbumStatGO;
import com.cyk.like_test.model.type.RedisKeyConst;
import com.cyk.like_test.model.vo.AlbumStatVO;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.dao.DataAccessException;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.SessionCallback;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.validation.constraints.NotBlank;
import java.util.List;


@Validated
@RestController
@RequestMapping("/album/read")
public class AlbumReadApi {

    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    @Resource
    private RabbitTemplate rabbitTemplate;

    @Resource
    private MongoTemplate mongoTemplate;

    @GetMapping("/mysql/one")
    public AlbumStatVO MySQLOne(
            @RequestParam @NotBlank String albumId
    ) {
        //为了简单，只设计了点赞表，因此这里通过四次查询点赞表来模拟
        Long pageView = Db.lambdaQuery(AlbumLike.class)
                .eq(AlbumLike::getTargetId, albumId)
                .count();
        Long likeCnt = Db.lambdaQuery(AlbumLike.class)
                .eq(AlbumLike::getTargetId, albumId)
                .count();
        Long collectCnt = Db.lambdaQuery(AlbumLike.class)
                .eq(AlbumLike::getTargetId, albumId)
                .count();
        Long commentCnt = Db.lambdaQuery(AlbumLike.class)
                .eq(AlbumLike::getTargetId, albumId)
                .count();
        if(pageView == null || likeCnt == null || commentCnt == null || collectCnt == null) {
            return null;
        }
        return AlbumStatVO.builder()
                .albumId(Long.valueOf(albumId))
                .pageView(pageView)
                .likeCnt(likeCnt)
                .collectCnt(collectCnt)
                .commentCnt(commentCnt)
                .build();
    }

    @GetMapping("/mysql/two")
    public AlbumStatVO MySQLTwo(
            @RequestParam @NotBlank String albumId
    ) {
        AlbumStat stat = Db.lambdaQuery(AlbumStat.class)
                .eq(AlbumStat::getAlbumId, albumId)
                .one();
        if(stat == null) {
            return null;
        }
        return AlbumStatVO.builder()
                .albumId(Long.valueOf(albumId))
                .pageView(stat.getPageView())
                .likeCnt(stat.getLikeCnt())
                .collectCnt(stat.getCollectCnt())
                .commentCnt(stat.getCommentCnt())
                .build();
    }

    @GetMapping("/redis/one")
    public AlbumStatVO redisOne(
            @RequestParam @NotBlank String albumId
    ) {
        //1.redis 是否有
        List<Object> statList = redisTemplate.executePipelined(new SessionCallback<String>() {
            @Override
            public <K, V> String execute(RedisOperations<K, V> operations) throws DataAccessException {
                RedisOperations<String, Object> template = (RedisOperations<String, Object>) operations;
                template.opsForValue().get(RedisKeyConst.ALBUM_PAGE_VIEW + albumId);
                template.opsForSet().size(RedisKeyConst.ALBUM_LIKE + albumId);
                template.opsForValue().get(RedisKeyConst.ALBUM_COLLECT + albumId);
                template.opsForValue().get(RedisKeyConst.ALBUM_COMMENT + albumId);
                return null;
            }
        });
        if(statList.get(0) != null && statList.get(1) != null
                && statList.get(2) != null && statList.get(3) != null) {
            return AlbumStatVO.builder()
                    .albumId(Long.valueOf(albumId))
                    .pageView((Long) statList.get(0))
                    .likeCnt((Long) statList.get(1))
                    .collectCnt((Long) statList.get(2))
                    .commentCnt((Long) statList.get(3))
                    .build();
        }
        //2.redis上没有，去查数据库
        AlbumStat dbStat = Db.lambdaQuery(AlbumStat.class)
                .eq(AlbumStat::getAlbumId, albumId)
                .one();
        if(dbStat == null) {
            return null;
        }
        List<Long> userIds = Db.lambdaQuery(AlbumLike.class)
                .eq(AlbumLike::getTargetId, albumId)
                .list().stream()
                .map(AlbumLike::getPostId)
                .toList();

        //3.将数据保存到 redis 上
        redisTemplate.executePipelined(new SessionCallback<Object>() {
            @Override
            public <K, V> Object execute(RedisOperations<K, V> operations) throws DataAccessException {
                RedisOperations<String, Object> temp = (RedisOperations<String, Object>) operations;
                temp.opsForValue().set(RedisKeyConst.ALBUM_PAGE_VIEW + albumId, dbStat.getPageView());
                temp.opsForSet().add(RedisKeyConst.ALBUM_LIKE + albumId, userIds.toArray()); //第二个参数是数组
                temp.opsForValue().set(RedisKeyConst.ALBUM_COLLECT + albumId, dbStat.getCollectCnt());
                temp.opsForValue().set(RedisKeyConst.ALBUM_COMMENT + albumId, dbStat.getCommentCnt());
                return null;
            }
        });

        return AlbumStatVO.builder()
                .albumId(Long.valueOf(albumId))
                .pageView(dbStat.getPageView())
                .likeCnt(dbStat.getLikeCnt())
                .commentCnt(dbStat.getCommentCnt())
                .collectCnt(dbStat.getCollectCnt())
                .build();
    }

    @GetMapping("/mongo/one")
    public AlbumStatVO mongoOne(
            @RequestParam String albumId
    ) {
        AlbumStatGO statGO = mongoTemplate.findOne(
                Query.query(
                        Criteria
                                .where("_id")
                                .is(Long.valueOf(albumId)))
                , AlbumStatGO.class);
        if(statGO == null) {
            return null;
        }
        return AlbumStatVO.builder()
                .albumId(Long.valueOf(albumId))
                .pageView(statGO.getPageView())
                .likeCnt(statGO.getLikeCnt())
                .commentCnt(statGO.getCommentCnt())
                .collectCnt(statGO.getCollectCnt())
                .build();
    }


}
